<?php

namespace app\wechat\service;

use app\admin\service\BaseService;
use app\wechat\model\ApplicationModel;
use app\wechat\model\MiniCodeModel;
use app\wechat\model\MiniPhoneNumberModel;
use app\wechat\model\MiniUserModel;
use EasyWeChat\Factory;
use Exception;
use think\facade\App;
use think\facade\Db;

/**
 * 小程序服务类
 *
 * @Author tanruizheng
 * @DateTime 2021-08-17
 */
class MiniService extends BaseService
{
    public $app;

    protected $appId;

    /**
     * app实例
     *
     * @Author tanruizheng
     * @DateTime 2021-08-10
     * @return object
     */
    public function getApp(){
        return $this->app;
    }

    public function __construct($appId)
    {
        $application = ApplicationModel::where(
            [
                'app_id'        => $appId,
                'account_type'  => ApplicationModel::ACCOUNT_TYPE_MINI
            ]
        )->findOrEmpty()->toArray();
        if(empty($application)){
           throw new Exception('应用信息不存在');
        }
        $config = [
            'app_id' => $application['app_id'],
            'secret' => $application['secret'],
        ];
        $this->appId = $appId;
        $this->app = Factory::miniProgram($config);
    }

    /**
     * 微信小程序用户信息授权
     *
     * @Author tanruizheng
     * @DateTime 2021-08-17
     * @param [type] $code
     * @return void
     */
    public function getUserInfo($code, $iv, $encryptedData){
        $res = $this->app->auth->session($code);
        $sessionKey = $res['session_key'];
        if(!empty($sessionKey)){
            $openid = $res['openid'];
            $unionid = isset($res['unionid']) ? $res['unionid'] : '';
            $info = $this->app->encryptor->decryptData($sessionKey, $iv, $encryptedData);
            if(!empty($info)){
                Db::startTrans();
                try {
                    //微信微信公众号用户信息
                    $MiniUserModel = MiniUserModel::where('open_id',$openid)->findOrEmpty();
                    $MiniUserModel->app_id = $this->appId;
                    $MiniUserModel->open_id = $openid;
                    $MiniUserModel->nick_name = $info['nickName'];
                    $MiniUserModel->gender = $info['gender'];
                    $MiniUserModel->language = $info['language'];
                    $MiniUserModel->city = $info['city'];
                    $MiniUserModel->province = $info['province'];
                    $MiniUserModel->country = $info['country'];
                    $MiniUserModel->avatar_url = $info['avatarUrl'];
                    $MiniUserModel->union_id = $unionid;
                    $MiniUserModel->save();
                    //生成Token信息
                    $authTokenService = new AuthTokenService();
                    $res = $authTokenService->createAuthToken($this->appId,$openid,'mini');
                    Db::commit();
                    $MiniUserInfo = $MiniUserModel->toArray();
                    return self::createSuccess('success',array_merge($MiniUserInfo,[
                        'token'         => $res['token'],
                        'expire_time'   => $res['expire_time'],
                        'refresh_token' => $res['refresh_token'],
                    ]));
                } catch (\Exception $e) {
                    Db::rollback();
                    return self::createFail($e->getMessage());
                }
            }else{
                return self::createFail('解析用户信息失败');
            }
        }else{
            return self::createFail('获取session_key失败');
        }
    }

    /**
     * 微信小程序手机号码授权
     *
     * @Author tanruizheng
     * @DateTime 2021-08-23
     * @param [type] $code
     * @param [type] $iv
     * @param [type] $encryptedData
     * @return void
     */
    public function getPhoneNumber($code, $iv, $encryptedData){
        $res = $this->app->auth->session($code);
        $sessionKey = $res['session_key'];
        if(!empty($sessionKey)){
            $openid = $res['openid'];
            $info = $this->app->encryptor->decryptData($sessionKey, $iv, $encryptedData);
            if(!empty($info)){
                Db::startTrans();
                try {
                    //微信公众号用户授权手机号码
                    $MiniPhoneNumberModel = MiniPhoneNumberModel::where('open_id',$openid)->findOrEmpty();
                    $MiniPhoneNumberModel->app_id = $this->appId;
                    $MiniPhoneNumberModel->open_id = $openid;
                    $MiniPhoneNumberModel->country_code = $info['countryCode'];
                    $MiniPhoneNumberModel->phone_number = $info['phoneNumber'];
                    $MiniPhoneNumberModel->pure_phone_number = $info['purePhoneNumber'];
                    $MiniPhoneNumberModel->save();
                    //生成Token信息
                    $authTokenService = new AuthTokenService();
                    $res = $authTokenService->createAuthToken($this->appId,$openid,'mini');
                    Db::commit();
                    $MiniPhoneNumberInfo = $MiniPhoneNumberModel->toArray();
                    return self::createSuccess('success',array_merge($MiniPhoneNumberInfo,[
                        'token'         => $res['token'],
                        'expire_time'   => $res['expire_time'],
                        'refresh_token' => $res['refresh_token'],
                    ]));
                } catch (\Exception $e) {
                    Db::rollback();
                    return self::createFail($e->getMessage());
                }
            }else{
                return self::createFail('解析用户信息失败');
            }
        }else{
            return self::createFail('获取session_key失败');
        }
    }

    /**
     * 获取小程序码
     * 
     * 适用于需要的码数量较少的业务场景
     *
     * @Author tanruizheng
     * @DateTime 2021-08-24
     * @return void
     */
    public function getLimitCode($path, $options = []){
        $response = $this->getApp()->app_code->get($path, $options);
        // 保存小程序码到文件
        if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
            $appcodeDir = App::getRootPath() . '/public/d/wechat/appcode';
            if(!is_dir($appcodeDir)){
                mkdir($appcodeDir, 0755, true);
            }
            $fileName = time() . rand(10000,99999).'.png';
            $res = $response->saveAs($appcodeDir, $fileName);
            if($res){
                $fileUrl = request()->domain() . '/d/wechat/appcode/' . $fileName;
                $MiniCodeModel = new MiniCodeModel();
                $MiniCodeModel->app_id = $this->appId;
                $MiniCodeModel->type = MiniCodeModel::CODE_TYPE_LIMIT;
                $MiniCodeModel->path = $path;
                $MiniCodeModel->file_name = $fileName;
                $MiniCodeModel->file_url = $fileUrl;
                $MiniCodeModel->save();
                return self::createSuccess('保存小程序码成功',[
                    'file_url' => $fileUrl,
                ]);
            }else{
                return self::createFail('保存小程序码');
            }
        }
    }
    /**
     * 获取小程序码
     * 
     * 适用于需要的码数量极多，或仅临时使用的业务场景
     *
     * @Author tanruizheng
     * @DateTime 2021-08-24
     * @return void
     */
    public function getUnlimitCode($scene, $options = []){
        $response = $this->getApp()->app_code->getUnlimit($scene, $options);
        // 保存小程序码到文件
        if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
            $appcodeDir = App::getRootPath() . '/public/d/wechat/appcode';
            if(!is_dir($appcodeDir)){
                mkdir($appcodeDir, 0755, true);
            }
            $fileName = time() . rand(10000,99999).'.png';
            $res = $response->saveAs($appcodeDir, $fileName);
            if($res){
                $fileUrl = request()->domain() . '/d/wechat/appcode/' . $fileName;
                $MiniCodeModel = new MiniCodeModel();
                $MiniCodeModel->app_id = $this->appId;
                $MiniCodeModel->type = MiniCodeModel::CODE_TYPE_UNLIMIT;
                $MiniCodeModel->path = isset($options['page']) ? $options['page'] : '';
                $MiniCodeModel->file_name = $fileName;
                $MiniCodeModel->file_url = $fileUrl;
                $MiniCodeModel->save();
                return self::createSuccess('保存小程序码成功',[
                    'file_url' => $fileUrl,
                ]);
            }else{
                return self::createFail('保存小程序码');
            }
        }
    }
}